home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-28 | 24.1 KB | 628 lines | [TEXT/R*ch] |
- Simple Sockets v 1.1
- Maintenance Release/Minor Upgrade
-
- by Michael Trent.
-
- 0. Manual Overview
- ~~~~~~~~~~~~~~~~~~
- (not quite a table of contents ... what with no page numbers and all)
-
- Section Topic
-
- 1. . . . . . . . Introduction
- 2. . . . . . . . Distribution
- 3. . . . . . . . Installation
- 4. . . . . . . . Using Simple Sockets
- 5. . . . . . . . Simple Socket Routines
- 6. . . . . . . . Making Your Own Spin Routines
- 7. . . . . . . . Error Handling
- 8. . . . . . . . Suggested Reading List
- 9. . . . . . . . Simple Sockets License Agreement
-
-
- 1. Introduction
- ~~~~~~~~~~~~~~~
-
- Simple Sockets arose out of an effort to port Sun Microsystems's RPCSRC 4.0 to
- the Macintosh operating system, using MacTCP for TCP/IP and UDP/IP support. RPC
- relies on BSD UNIX socket calls for Inter Process Communication, like any good
- UNIX software should. After tinkering with a number of socket solutions for the
- Macintosh (GUSI, some weird BSD source I received from University of Toronto, and
- so on), I decided to bite the bullet and simulate BSD sockets myself.
-
- BSD compatibility has not been my primary goal however. There are a number of
- facets of UNIX socket calls that are artifacts of earlier systems, remaining for
- backwards compatibility. Also socket calls are designed to be more flexible than
- MacTCP can be. So, some calls were simplified a bit for the sake of "progress".
-
- As a result, most UNIX socket code won't compile without some modification
- (perhaps this makes the code useless to most people). As time permits, I hope to
- close the gap between Simple Sockets and BSD sockets a little more.
-
- On the off chance that someone might find this code useful, I am willingly giving
- all this code up into the Public Domain (my friends say "Sell It! Sell It!", but
- some perverse sense of virtue prevents me from charging money for anything I
- think is valuable - see my notoriously unpopular shareware program "CPU Reporter"
- for the corrollary: charge money for useless software). If someone out there
- makes some changes to my code that are valuable additions or bug fixes, I'd love
- to hear about it, so I can update my master copies. I hope to post updates to
- the Info-Mac archive when-and-if changes occur.
-
- Of course, there are other BSD Socket implementations out there, some of them
- much better than my humble project (again: GUSI). If you think this project has
- any value at all, please drop me a line, e- or snail- mail. I can be reached at:
-
- Michael D. Trent
- 3302 Leopold Way #110
- Madison, WI 53713
-
- work e-mail: mtrent@epicsys.com
- pleasure e-mail: mtrent@msn.fullfeed.com
-
- E-mail is preferred. Please try my "pleasure" e-mail first — I do check it
- daily.
-
- Oh, and this is version 1.1. For a short list of changes, see the "Read Me
- First" file, if you haven't already. If you get a chance, glance at "To Do" as
- well. Enjoy!
-
-
- 2. Distribution
- ~~~~~~~~~~~~~~~
-
- The Simple Sockets archive contains a number of important directories, including:
-
- butil ƒ
-
- This directory includes a small library (butil.c) for supporting UNIX binary
- utilities, such as bcmp, bcopy, bzero, and ffs. These routines are handy,
- even though they are far from optimized.
-
- ip ƒ
-
- Here lies the networking code. The bulk of the code can be found in ip.c,
- the application level interface, and iplow.c, the MacTCP level interface. The
- remaining files (ipdr.c, iperr.c, iptime.h, etc.) provide less important
- features.
-
- MacTCP Headers ƒ
-
- MacTCP header files for both the Universal Headers and for older pre-UH
- systems (i.e., THINK C 5.0.4). See the “Headers ReadMe” in this directory
- for more information.
-
- Sample Apps ƒ
-
- A pair of sample applications have been provided to demonstrate Simple
- Sockets in action. The programs are probably buggy (I know of one problem
- with the MacDayd program for sure), and do very little error reporting. As
- further evidence that I hacked them up in an hour, the code is a little hard
- to read in spots. Still, they should give one some idea of how to use the
- Simple Sockets library.
-
- The sample programs, MacDay and MacDayd, are modeled after some examples in
- Comer's Internetworking with TCP/IP vol III. It seems that by pinging port
- 13 of any UNIX machine, that machine will tell you what time it thinks it is.
- MacDay is a client program for the DAYTIME service, while MacDayd is a simple
- server to allow one's Macintosh to accept DAYTIME queries. These programs
- are much less interesting than any Peter N. Lewis program.
-
-
- 3. Installation
- ~~~~~~~~~~~~~~~
-
- Projects that use Simple Sockets need to have access to the butil ƒ and ip ƒ
- directories, as well as the headers for MacTCP. Please refer to your compiler
- documentation for information on how to do this. With Metrowerks CodeWarrior,
- three different strategies leap to my mind:
-
- 1) Go into your project's preferences and set the project's Access Path to
- include both directories. While this works, it's a little tedious to do
- once, never mind more several projects.
-
- 2) Copy the directories into the application's project directory. Of course,
- if you are planning on writing lots of different Simple Sockets apps, you'll
- be doing a lot of copying.
-
- 3) Move the directories into the same folder as your Metrowerks compiler. I
- am personally quite fond of this solution, personally.
-
- Note: Metrowerks Codewarrior 7.0 complicates this a little. The compiler no
- longer looks for code in it's directory. You'll need to bury the routines in
- one of the compiler's subdirectories. See the Metrowerks documentation for
- more details.
-
- I believe these strategies will also work with the THINK compilers.
-
-
- 4. Using Simple Sockets
- ~~~~~~~~~~~~~~~~~~~~~~~
-
- Using Simple Sockets is relatively easy, especially for those programmers with
- UNIX socket programming experience. As I have alluded to already, some Simple
- Socket routines are similar to, but not identical to, their UNIX counterparts.
- These differences will be explained later in this document.
-
- The following files must be added to one's project: butil.c, ip.c, iperr.c, and
- iplow.c. ipdr.c is optional, and is probably only necessary if you are porting
- some existing UNIX code to the Macintosh.
-
- The file MacTCPCommonTypes.h must be #included before any ip files are. For
- basic socket support, one would include:
-
- #include <MacTCPCommonTypes.h>
-
- #include "ip.h"
- #include "iperr.h"
-
- The Simple Sockets library must be initialized at run time before any socket
- routines are called. The routine "InitMacTCP" opens the MacTCP driver and
- performs some additional house-keeping. It shouldn't hurt to place InitMacTCP in
- your ToolBoxInit (or whatever) procedure.
-
- Before the program terminates, it must make sure that all active sockets are
- closed. If a program quits without letting MacTCP know a stream is free, MacTCP
- can (and will!) crash the entire machine in a blaze of glory (if you don't
- believe me, force quit NCSA Telnet a few times). To be safe, you can call
- "DisposeMacTCP" before quitting; DisposeMacTCP will close all remaining streams
- for you. (Tip: Make sure you call this at the end of the program, and before any
- "ExitToShell" calls!)
-
- All socket calls are asynchronous. While a program is waiting for some network
- transaction to take place, the computer continues multi-tasking away. This is
- provided in part by a secondary event loop (called a "Spin Routine"), which calls
- WaitNextEvent and provides basic event processing. In order to provide spinning
- cursors or Dialogs with "Cancel" buttons, you must define your own Spin Routine;
- see "Making Your Own Spin Routines" below for more information.
-
-
- 5. Simple Socket Routines
- ~~~~~~~~~~~~~~~~~~~~~~~~~
-
- At this time, only the routines in ip.c and ipdr.c are documented in this manual.
- Routines in other files are either fairly straight forward (IMHO) or they
- shouldn't be of much use to other people (e.g., iplow.c). Other files may be
- documented here in the future.
-
-
- GENERAL ROUTINES
-
-
- InitMacTCP
-
- OSErr InitMacTCP(void)
-
- InitMacTCP must be called by the application before making other calls to
- routines in the Simple Sockets library. It initializes the MacTCP driver, clears
- the socket list, and sets the default spin routine.
-
-
- DisposeMacTCP
-
- void DisposeMacTCP(void)
-
- DisposeMacTCP should be called before an application terminates, or when it is
- done with the MacTCP driver. DisposeMacTCP closes all initialized sockets, and
- disposes sockets' buffer memory.
-
-
- SetSpin
-
- void SetSpin(Spin spinRoutine)
-
- SetSpin sets the spin routine. The spin routine is a secondary event loop called
- repeatedly by iplow.c while waiting for MacTCP calls to complete. This allows
- other processes on the Macintosh to continue operating in their co-operative
- multi-tasking environment. For information on writing your own spin routine, see
- "Making Your Own Spin Routines" below.
-
-
- ADDRESS CONVERSION AND LOOKUP ROUTINES
-
-
- num2dot
-
- void num2dot(unsigned long ip, char *dot)
-
- num2dot is a small routine to convert an unsigned long ip number into the
- human-readable dot notation (e.g., 2421762054 becomes "144.89.40.6"). To be
- safe, dot should point to at least 16 bytes of memory.
-
- num2dot isn't part of BSD UNIX sockets.
-
-
- ConvertStrToAddr
-
- OSErr ConvertStrToAddr(char *name, unsigned long *ipNum)
-
- This routine converts strings to unsigned long ip numbers. The string can
- contain either a dot notation ip address (e.g., "144.89.40.6"), or a DNS host
- name (e.g., "stu.beloit.edu"). It returns an OSErr passed on from MacTCP.
-
- ConvertStrToAddr isn't part of BSD UNIX sockets.
-
-
- GetHostByName
-
- unsigned long GetHostByName(char *name)
-
- GetHostByName emulates the UNIX routine by the same name (gethostbyname is
- #defined as GetHostByName). Given a string containing a DNS name or a dot
- separated number, GetHostByName will return that host's unsigned long ip number.
- If an error occurs, GetHostByName will return 0.
-
-
- GetProtoByName
-
- int GetProtoByName(char *name)
-
- GetProtoByName roughly emulates the UNIX routine by the same name (getprotobyname
- is #defined as GetProtoByName in ip.h). Given a string containing the name of a
- network protocol, GetProtoByName will return the integer corresponding to it's
- protocol; it will return 0 if it doesn't recognize the protocol. Currently,
- GetProtoByName only understands "tcp" and "udp".
-
- This routine differs from the UNIX routine in that it returns a simple int,
- rather than a record of information. This is largely because MacTCP only
- understands TCP/IP and UDP/IP.
-
-
- GetHostName
-
- int GetHostName(char *name, int namelen)
-
- GetHostName emulates the UNIX routine by the same name (gethostname is #defined
- as GetHostName). GetHostName returns the name of the local computer in name. The
- routine returns 0 if successful; it will return -1 if an error occurred.
-
- Note: Since any given Macintosh may not have a local name (unlike UNIX machines
- which DO have local names), GetHostName will return the local host's
- dot-separated IP number if no DNS name exists for the local machine.
-
- Warning: Currently, namelen is unused, provided only for UNIX compatibility.
- name must point to a "sufficiently large" amount of memory. This should be fixed
- in the future.
-
-
- GetHostNameOnly
-
- int GetHostNameOnly(char *name)
-
- GetHostNameOnly is a spinoff of GetHostName. It is identical to GetHostName
- except that if the local host doesn't have a DNS name, GetHostNameOnly will fail,
- rather than returning a dot-separated IP number. name should point to a
- "sufficiently large" amount of memory. GetHostNameOnly returns 0 if successful;
- otherwise it returns -1.
-
-
- GetMyIPDot
-
- int GetMyIPDot(char *num)
-
- GetMyIPDot returns the dot-separated IP address of the local machine in num. num
- should point to at least 16 bytes of memory. GetMyIPDot returns 0 if successful;
- otherwise it returns -1.
-
- GetMyIPDot isn't part of BSD UNIX sockets.
-
-
- GetMyIPNum
-
- unsigned long GetMyIPNum(void)
-
- GetMyIPNum returns the unsigned long IP address of the local machine; it returns
- -1 if an error occurs.
-
- GetMyIPNum isn't part of BSD UNIX sockets.
-
-
- getsockname
-
- int getsockname (int sock, struct sockaddr_in *localaddr, int *addrlen)
-
- getsockname is identical to the UNIX function with the same name, except
- localaddr is a struct sockaddr_in * rather than a struct sockaddr *. localaddr
- points to a sockaddr_in struct containing the port and ip numbers of the local
- host. *addrlen will be set to the size of the sockaddr_in struct. getsockname
- returns 0 if successful; otherwise it returns -1.
-
- This routine was originally contributed by Lim Wai Kong David
- <limwaiko@iscs.nus.sg>.
-
-
- GENERAL IP ROUTINES
-
-
- socket
-
- int socket(int family, int type, int protocol)
-
- socket roughly emulates the UNIX function with the same name. The variables
- family and type are not used, they are provided solely for compatibility with
- UNIX code. The variable protocol must be either IPPROTO_TCP or IPPROTO_UDP.
- socket also reserves some memory for use by MacTCP. socket returns a socket
- number (currently between 0 and 31 inclusive) if successful; otherwise it returns
- -1.
-
-
- connect
-
- int connect(int sock, struct sockaddr_in *raddr, int alen)
-
- connect roughly emulates the UNIX function with the same name, except localaddr
- is a struct sockaddr_in * rather than a struct sockaddr *. If sock is a TCP
- socket, connect will open a connection from the local host to the remote host
- specified in *raddr. If sock is a UDP socket, the destination specified in raddr
- is recorded for use in other routines. connect returns 0 if successful; it
- returns -1 if an error occurs.
-
- Note: The variable alen is not used, it is provided solely for compatibility with
- UNIX code.
-
-
- bind
-
- int bind (int sock, struct sockaddr_in *name, int alen)
-
- bind roughly emulates the UNIX function with the same name. bind specifies a
- port for a server to listen to. sock may be either a UDP or TCP socket. A port
- may be bound to twice; once with a TCP socket, once with a UDP socket. bind
- returns 0 if successful; it returns -1 if an error occurs.
-
- Note: bind differs from the UNIX bind in several ways. First of all, name is a
- struct sockaddr_in * rather than a struct sockaddr *. Secondly, name->sin_addr
- traditionally is set to INADDR_ANY or the local system address; name->sin_addr is
- ignored in this implementation. Thirdly, in UNIX systems, ports 0 - 1023
- (inclusive) are reserved for privilaged processes; this implementation does not
- preserve the notion of reserved ports. Lastly, the variable alen is not used, it
- is provided solely for compatibility with UNIX code.
-
-
- listen
-
- int listen(int socket, int queuelen)
-
- listen is a dummy routine; provided only for UNIX compatibility. Both variables
- are completely ignored. listen always returns 0.
-
- If anyone can think of a way to REALLY implement listen, I'd be glad to hear it.
-
-
- write
-
- int write (int sock, Ptr data, int len)
-
- write is identical to the UNIX function with the same name. write sends len
- bytes pointed to by data across the active connection referenced by sock. sock
- must be a valid, connected socket; it can be either a TCP or UDP socket. write
- returns the number of bytes successfully written to the remote host; it returns
- -1 if an error prevents any data from being sent.
-
-
- read
-
- int read (int sock, Ptr buf, int len)
-
- read is identical to the UNIX function with the same name. read reads at most
- len bytes pointed to by data from the active connection referenced by sock. sock
- must be a valid, connected socket; it can be either a TCP or UDP socket. If
- there is no data outstanding, read will block until new data is received. read
- returns the number of bytes successfully read from the remote host; it returns -1
- if an error prevents any data from being read.
-
-
- close
-
- int close(int sock)
-
- close is identical to the UNIX function with the same name. close closes an
- active socket and releases its memory. close returns 0; it can return -1 if an
- error occurs.
-
-
- select
-
- int select (int nfds, unsigned long *readfs, struct timeval *timeout)
-
- select is used to find out if any unread data is outstanding on a socket before
- blocking the process with a read() or similar call. The argument list is a
- truncated version of the original UNIX; I've kept only the aspects of the call
- that are important to socket programmers (at least I believe I have).
-
- nfds is the number of file descriptors available on the system. While this can
- vary from UNIX system to UNIX system, you can count on the number of file
- descriptors known by Simple Sockets being 32 — as defined in ip.h as kNumSockets.
- Always pass this constant in as nfds.
-
- *readfs specifies the sockets one wants to query. It is no coincidence that
- while there are 32 socket descriptors in Simple Sockets, there are 32 bits in an
- unsigned long number. To specify a particular socket, set it's corresponding bit
- to 1; set all other bits to 0. When select returns, *readfs identifies sockets
- with incomming data outstanding in the same way.
-
- One can specify a length of time to wait for via *timeout. If *timeout is nil,
- select will poll once before returning, whether or not there is unread data. If
- *timeout is not nil, its fields describe the maximum amount of time select should
- wait before giving up and returning to the program.
-
- In addition to returning data via *readfs, select itself returns an integer for
- error detection. A return value of 0 indicates success, -1 indicates failure.
- Simple Socket's select will only return an error if a socket was flagged that is
- not an initialized socket.
-
- select is really used by advanced socket programmers — it's not really something
- I would expect a novice to understand just from reading this file. For more
- enlightenment, I must refer you to my "Suggested Reading List" (section 8).
-
- Note: In the source file ip.c, select is in a section of code labeled "TCP
- SECTION". This is in error; select does infact work with TCP and UDP sockets.
-
- Note: This version of select has one fatal flaw: it assumes that if you read from
- a socket which has data outstanding you intend to read ALL the data. I have made
- some modifications to read() in order to prevent this situation, but it only works
- for TCP sockets.
-
-
- TCP ROUTINES
-
-
- accept
-
- int accept (int sock, struct sockaddr_in *sin, int *alen)
-
- accept roughly emulates the UNIX routine by the same name. accept passively
- waits for a TCP connection on socket sock. When a remote client connects to the
- local port described in sock, accept returns a socket number describing the local
- connection, and *sin contains the address and port of the client. Confused?
- Please consult Comer and other UNIX texts.
-
- Note: sin is a struct sockaddr_in * rather than a struct sockaddr *. Also the
- variable alen is not used, it is provided solely for compatibility with UNIX
- code.
-
-
- UDP ROUTINES
-
-
- recvfrom
-
- int recvfrom (int sock, char *buf, int len, int flags,
- struct sockaddr_in *sin, int *alen)
-
- recvfrom roughly emulates the UNIX routine by the same name. It allows a program
- to passively wait for UDP socket information. sock is a valid UDP socket, buf
- points to a number of bytes in memory, len is the size of memory pointed to by
- buf, and *sin contains the address and port of the client upon return. If *sin
- is nil, packets will be accepted from any client.
-
- Note: sin is a struct sockaddr_in * rather than a struct sockaddr *. Also the
- variables alen and flags are not used, they are provided solely for compatibility
- with UNIX code.
-
-
- sendto
-
- int sendto (int sock, char *data, int len, int flags,
- struct sockaddr_in *sin, int alen)
-
- sendto roughly emulates the UNIX routine by the same name. It allows a program
- to send data across a UDP stream. sock is a valid UDP socket, data points to a
- number of bytes in memory, len is the size of memory pointed to by data, and *sin
- contains the address and port of the server.
-
- Note: sin is a struct sockaddr_in * rather than a struct sockaddr *. Also the
- variables alen and flags are not used, they are provided solely for compatibility
- with UNIX code.
-
-
- DATA REPRESENTATION (ipdr.c)
-
-
- int htons(int x)
- int ntohs(int x)
- long htonl(long y)
- long ntohl(long y)
-
- These routines are provided for UNIX compatibility. Since the Macintosh byte
- ordering is identical to "Network byte ordering" these routines do nothing. They
- simply return their arguments.
-
-
- 6. Making Your Own Spin Routines
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- Spin Routines provide simple event processing, allowing the Macintosh to continue
- multi-tasking while waiting for a MacTCP call to return. Rather than processing
- events in an event loop, Spin Routines should process only a few events at a time
- before returning.
-
- A Spin Routine has the following header:
-
- OSErr MySpinRoutine (void)
-
- Note: Because the routine will be called by the Simple Sockets library and not
- by the Macintosh operating system, it shouldn't be prefixed with the "pascal"
- keyword.
-
- These routines can be used to poll for user input even while the program is
- waiting for a MacTCP call to return. For example, the default spin routine
- provided by Simple Sockets allows the user to press "esc", which will cause the
- current MacTCP call to fail. One could easily create a window with a Cancel
- button, make a socket call, and use a custom Spin Routine to handle that button.
-
- For an example Spin Routine, see the file iplow.c; the default spin routine is
- named "SpinDefault".
-
-
- 7. Error Handling
- ~~~~~~~~~~~~~~~~~~
-
- UNIX programs rely on the standard errno variable and other standard functions to
- provide error reporting. Unfortunately, the Macintosh doesn't have anything
- quite like that. Currently, Simple Sockets provides similar error reporting with
- two global variables: gErrno and gMacErrno. gErrno is essentially the same as
- the UNIX errno variable; gMacErrno will contain the normal Macintosh OSErr error
- number if the error was caused by a Macintosh routine. If an error occurs, make
- sure you check both variables.
-
- By my own admission, error reporting in Simple Sockets is pretty weak. This
- should improve in the future.
-
-
- 8. Suggested Reading List
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- The following is a list of works I suggest looking into if you are interested in
- socket or MacTCP programming. This list includes books, electronic documents,
- World Wide Web pages, and the like.
-
-
- Apple Computer, Inc.. MacTCP Programmer's Guide, Apple Computer, Inc., 1991.
- (available via WWW at one of Apple's many Web servers)
-
- Comer, Douglas E., David L. Stevens. Internetworking with TCP/IP, Volume III.
- Prentice Hall: Englewood Cliffs, New Jersey.
-
- Lentz, Robert. Robert Lentz's Macintosh Programming Resources. WWW Pages.
- (URL: http://www.astro.nwu.edu/lentz/mac/programming/home-prog.html)
-
- Stevens, Richard W.. UNIX Network Programming. Prentice Hall: Englewood Cliffs,
- New Jersey.
-
-
- 9. Simple Sockets License Agreement
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- Simple Sockets is offered directly to the public domain. I request that it is
- not modified in any way and that it is accompanied by all of the original
- documentation unaltered. This is only a request.
-
- Disclaimer of warranty:
- In using this software, you understand and agree that this software is provided
- “as is” without warranty of any kind. The entire risk as to the results and
- performance of using this software lies entirely with you, the user. The author
- does not make any warranties, either expressed or implied, including but not
- limited to implied warranties of merchantability and fitness for a particular
- purpose, with respect to this software.
-
- In no event shall the author be liable for any consequential, incidental, or
- special damages whatsoever (including without limitation damages for loss of
- critical data, loss of profits, interruption of business, and the like) arising
- out of the use or inability to use this software. Because some states do not
- allow the exclusion or limitation of liability for consequential or incidental
- damages, the above limitations may not apply to you.
-
- Although the author would appreciate any feedback and bug reports, the author
- shall not be responsible for correcting any problems which you discover or
- otherwise help you maintain and use this software. Furthermore, the author may
- at any time replace, modify, alter, improve, enhance or change this software.
-
- Complete agreement:
- This agreement constitutes the entire agreement and supersedes any prior
- agreements between you and the author concerning this software. This agreement
- cannot be amended, modified, or waived except in writing.
-
- General:
- If any provision of this agreement shall be found to be unenforceable, it shall
- be deemed severed from the remainder of this agreement.
-